// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Validate.cs" company="CSLib.Net Team">
//   Copyright (c) Roman "4ux-nbIx" Novitsky 2010
// </copyright>
// <summary>
//   Defines validation methods.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace CSLib.Net.Diagnostics
{
  using System;
  using System.Diagnostics;
  using System.Globalization;

  using Annotations;

  // ReSharper disable ValueAnalysis

  /// <summary>
  /// Defines validation methods.
  /// </summary>
  [DebuggerStepThrough]
  [DebuggerNonUserCode]
  [UsedImplicitly(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.WithMembers)]
  public static class Validate
  {
    /// <summary>
    /// Validates that the specified argument is not <c>null</c>.
    /// </summary>
    /// <param name="argument">An argument value to check.</param>
    /// <param name="argumentName">A name of an argument.</param>
    /// <exception cref="ArgumentNullException"><paramref name="argument" /> is <c>null</c>.</exception>
    [AssertionMethod]
    public static void ArgumentNotNull(
      [AssertionCondition(AssertionConditionType.IS_NOT_NULL)] object argument, 
      [InvokerParameterName] [NotNull] string argumentName)
    {
      if (argument != null)
      {
        return;
      }

      string detailMessage = string.Format(CultureInfo.InvariantCulture, "{0} is null.", argumentName);

      throw new ArgumentNullException(argumentName, detailMessage);
    }


    /// <summary>
    /// Asserts that the specified argument value is not <c>null</c> or white space.
    /// </summary>
    /// <param name="value">
    /// The value to check.
    /// </param>
    /// <param name="argumentName">
    /// Name of the argument.
    /// </param>
    /// <exception cref="ArgumentNullException">Argument is <c>null</c>.</exception>
    [AssertionMethod]
    public static void ArgumentNotNullOrEmpty(
      [AssertionCondition(AssertionConditionType.IS_NOT_NULL)] string value, 
      [InvokerParameterName] [NotNull] string argumentName)
    {
      if (!string.IsNullOrEmpty(value))
      {
        return;
      }

      string detailMessage = string.Format(CultureInfo.InvariantCulture, "{0} is null or empty.", argumentName);

      throw new ArgumentNullException(argumentName, detailMessage);
    }


    /// <summary>
    /// Asserts that the specified argument value is not <c>null</c> or white space.
    /// </summary>
    /// <param name="value">
    /// The value to check.
    /// </param>
    /// <param name="argumentName">
    /// Name of the argument.
    /// </param>
    /// <exception cref="ArgumentNullException">Argument is <c>null</c>.</exception>
    [AssertionMethod]
    public static void ArgumentNotNullOrWhiteSpace(
      [AssertionCondition(AssertionConditionType.IS_NOT_NULL)] string value, 
      [InvokerParameterName] [NotNull] string argumentName)
    {
      if (!value.IsNullOrWhiteSpace())
      {
        return;
      }

      string detailMessage = string.Format(CultureInfo.InvariantCulture, "{0} is null or whitespace.", argumentName);

      throw new ArgumentNullException(argumentName, detailMessage);
    }

    /// <summary>
    /// Validates that the specified value is not <c>null</c>.
    /// </summary>
    /// <param name="value">The value to check.</param>
    /// <param name="messageFormat">A composite format <see cref="string"/>.</param>
    /// <param name="messageArguments">An array of message arguments to format.</param>
    /// <exception cref="InvalidOperationException"><c>Invalid Operation Exception</c>.</exception>
    [AssertionMethod]
    [StringFormatMethod("messageFormat")]
    public static void IsNotNull(
      [AssertionCondition(AssertionConditionType.IS_NOT_NULL)] object value,
      [NotNull] string messageFormat,
      [CanBeNull] params object[] messageArguments)
    {
      if (value != null)
      {
        return;
      }

      ThrowException(messageFormat, messageArguments);
    }

    /// <summary>
    /// Validates that the specified value is not <c>null</c> or white space.
    /// </summary>
    /// <param name="value">The value to check.</param>
    /// <param name="messageFormat">A composite format <see cref="string"/>.</param>
    /// <param name="messageArguments">An array of message arguments to format.</param>
    /// <exception cref="InvalidOperationException"><c>Invalid Operation Exception</c>.</exception>
    [AssertionMethod]
    [StringFormatMethod("messageFormat")]
    public static void IsNotNullOrEmpty(
      [AssertionCondition(AssertionConditionType.IS_NOT_NULL)] string value,
      [NotNull] string messageFormat,
      [CanBeNull] params object[] messageArguments)
    {
      if (!string.IsNullOrEmpty(value))
      {
        return;
      }

      ThrowException(messageFormat, messageArguments);
    }


    /// <summary>
    /// Validates that the specified value is not <c>null</c> or white space.
    /// </summary>
    /// <param name="value">The value to check.</param>
    /// <param name="messageFormat">A composite format <see cref="string"/>.</param>
    /// <param name="messageArguments">An array of message arguments to format.</param>
    /// <exception cref="InvalidOperationException"><c>Invalid Operation Exception</c>.</exception>
    [AssertionMethod]
    [StringFormatMethod("messageFormat")]
    public static void IsNotNullOrWhiteSpace(
      [AssertionCondition(AssertionConditionType.IS_NOT_NULL)] string value,
      [NotNull] string messageFormat,
      [CanBeNull] params object[] messageArguments)
    {
      if (!value.IsNullOrWhiteSpace())
      {
        return;
      }

      ThrowException(messageFormat, messageArguments);
    }


    /// <summary>
    /// Validates that the specified value is <c>false</c>.
    /// </summary>
    /// <param name="value">
    /// The value to validate.
    /// </param>
    /// <param name="messageFormat">
    /// The message format.
    /// </param>
    /// <param name="messageArguments">
    /// The message arguments.
    /// </param>
    /// <exception cref="System.InvalidOperationException"><c>Invalid Operation Exception</c>.</exception>
    [StringFormatMethod("messageFormat")]
    public static void IsFalse(bool value, [NotNull] string messageFormat, [CanBeNull] params object[] messageArguments)
    {
      Assert.ArgumentNotNull(messageFormat, "messageFormat");

      if (!value)
      {
        return;
      }

      ThrowException(messageFormat, messageArguments);
    }


    /// <summary>
    /// Validates that the specified value is <c>true</c>.
    /// </summary>
    /// <param name="value">
    /// The value to validate.
    /// </param>
    /// <param name="messageFormat">
    /// The message format.
    /// </param>
    /// <param name="messageArguments">
    /// The message arguments.
    /// </param>
    /// <exception cref="System.InvalidOperationException"><c>Invalid Operation Exception</c>.</exception>
    [StringFormatMethod("messageFormat")]
    public static void IsTrue(bool value, [NotNull] string messageFormat, [CanBeNull] params object[] messageArguments)
    {
      Assert.ArgumentNotNull(messageFormat, "messageFormat");

      if (value)
      {
        return;
      }

      ThrowException(messageFormat, messageArguments);
    }


    /// <summary>
    /// Throws the exception.
    /// </summary>
    /// <param name="messageFormat">
    /// The message format.
    /// </param>
    /// <param name="messageArguments">
    /// The message arguments.
    /// </param>
    /// <exception cref="InvalidOperationException">
    /// <c>Invalid Operation Exception</c>.
    /// </exception>
    private static void ThrowException([NotNull] string messageFormat, [CanBeNull] object[] messageArguments)
    {
      Assert.ArgumentNotNull(messageFormat, "messageFormat");

      string message = string.Format(CultureInfo.InvariantCulture, messageFormat, messageArguments);

      throw new InvalidOperationException(message);
    }
  }
}